#include "forco_os.h"

//定义17个时基链表
OS_TICK_LIST OSCfg_TickWheel[OSCfg_TickWheelSize];
//时基计数
CPU_UINT32   OSTickCtr =0 ;
extern OS_TCB      *OSTCBCurPtr; 
extern OS_TCB      IDLETaskTCB;

//初始化时基表
void OS_TickListInit(void)
{
    OS_TICK_LIST *p_tick_list;
    CPU_UINT8   i;
    for(i=0;i<OSCfg_TickWheelSize;i++){
        p_tick_list             = (OS_TICK_LIST*)&OSCfg_TickWheel[i];
        p_tick_list->Ticknext   = (OS_TCB*)0;
        p_tick_list->TickCount  = 0; 
    }
}

//插入一个任务控制块到时基表中,升序排序
void OS_TickListInset(OS_TCB *p_tcb,CPU_UINT32 time,OS_ERR *p_err)
{
    CPU_UINT8           i;
    OS_TICK_LIST        *p_tick_list;
    OS_TCB              *p_tcb1;
    OS_TCB              *p_tcb0;
    //任务的到期时间和剩余时间
    p_tcb->TickCtrMatch         = OSTickCtr + time;
    p_tcb->TickRemain           = time;
    //修改任务状态
    p_tcb->TaskState            = OS_TASK_STATE_DLY;
    //根据到期时间决定插入到那个链表上
    i               = (p_tcb->TickCtrMatch)%OSCfg_TickWheelSize;  
    p_tick_list     = &OSCfg_TickWheel[i];
    //第一种情况,链表为空，插入在最前面
    if(p_tick_list->TickCount == 0){
        p_tcb->TCBTickNextPtr       = (OS_TCB*)0;
        p_tcb->TCBTickPrevPtr       = (OS_TCB*)0;
        p_tick_list->Ticknext       =  p_tcb;
        p_tick_list->TickCount      =  1;
    }else{
        //获取链表头的第一个任务控制块
        p_tcb1      = p_tick_list->Ticknext;
        while(p_tcb1 != (OS_TCB*)0){
            //计算剩余时间
            p_tcb1->TickRemain      = p_tcb1->TickCtrMatch - OSTickCtr;
            //插入在后面
            if(p_tcb->TickRemain > p_tcb1->TickRemain){
                //插入在最后面
                if(p_tcb1->TCBTickNextPtr != (OS_TCB*)0){
                    p_tcb1 = p_tcb1->TCBTickNextPtr;
                }else{
                    p_tcb->TCBTickNextPtr   = (OS_TCB*)0;
                    p_tcb->TCBTickPrevPtr   = p_tcb1;
                    p_tcb1->TCBTickNextPtr  = p_tcb;
                    p_tcb1                  = (OS_TCB*)0;
                }
            }else{
                /*第一个节点插入*/
                if(p_tcb1->TCBTickPrevPtr == (OS_TCB*)0){
                   p_tcb->TCBTickPrevPtr    = (OS_TCB*)0;
                   p_tcb->TCBTickNextPtr    = p_tcb1;
                   p_tcb1->TCBTickPrevPtr   = p_tcb;
                   p_tick_list->Ticknext    = p_tcb; 
                }else{
                //在两者之间插入
                 p_tcb0                     = p_tcb1->TCBTickPrevPtr;
                 p_tcb->TCBTickPrevPtr      = p_tcb0;
                 p_tcb->TCBTickNextPtr      = p_tcb1;
                 p_tcb0->TCBTickNextPtr     = p_tcb;
                 p_tcb1->TCBTickPrevPtr     = p_tcb;
                }
                p_tcb1 = (OS_TCB*)0;
            }
        }
        //链表节点数++
        p_tick_list->TickCount++;
    }
    p_tcb->TickSpokePtr     = p_tick_list;
    *p_err = OS_ERR_NONE;
}

//将一个任务控制块从时基表中删除
void  OS_TickListRemove(OS_TCB *p_tcb)
{
  OS_TICK_LIST  *p_list;
  OS_TCB        *p_tcb1;
  OS_TCB        *p_tcb2;
  //获取tcb在那个时基序列上
  p_list    = p_tcb->TickSpokePtr;
  //确保删除的任务控制块在时基序列上
  if(p_list != (OS_TICK_LIST*)0){
    p_tcb->TickRemain   = 0;
    //删除的是第一个
    if(p_tcb == p_list->Ticknext) {
        p_tcb1                  = p_tcb->TCBTickNextPtr;
        p_list->Ticknext        = p_tcb1;
        if(p_tcb1 != (OS_TCB*)0){
            p_tcb1->TCBTickPrevPtr  = (OS_TCB*)0;
            }
        }
        else{
          p_tcb1                    = p_tcb->TCBTickPrevPtr;
          p_tcb2                    = p_tcb->TCBTickNextPtr;
          //将删除后的两个节点连起来
          p_tcb1->TCBTickNextPtr    = p_tcb2;
          if(p_tcb2 != (OS_TCB*)0){
            p_tcb2->TCBTickPrevPtr  = p_tcb1;
          }
        }
        //初始化ptcb中和时基相关的成员
        p_tcb->TCBTickNextPtr   = (OS_TCB*)0;
        p_tcb->TCBTickPrevPtr   = (OS_TCB*)0;
        p_tcb->TickSpokePtr     = (OS_TICK_LIST*)0;
        p_tcb->TickCtrMatch     = (CPU_UINT32)0;
        p_list->TickCount--;
  }
}

//时基更新,在每一个时间周期来的时候更新
void OS_TickListUpdate(void)
{
    OS_TICK_LIST *p_list;
    CPU_UINT32  ix;
    CPU_UINT32  flag = 0;
    OS_TCB      *p_tcb;
    OS_TCB      *p_tcb_next;
    CPU_SR_ALLOC();
    OS_CRITICAL_ENTER();
    OSTickCtr++;
    //根据当前时间来决定计算那个链表上到内容
    ix        = OSTickCtr%OSCfg_TickWheelSize;
    p_list    = &OSCfg_TickWheel[ix];
    //获取数组列表的第一个任务控制块
    p_tcb     = p_list->Ticknext;
    //完成标志设置为0
    flag      = 0x00;
    //时基表少更新了一个
    while (flag == 0){
      //获取到的任务控制块不为空
      //清空这个时基序列上挂载的所有的
      if(p_tcb != (OS_TCB*)0){
            //下一个任务控制块
            p_tcb_next                =   p_tcb->TCBTickNextPtr;
            //计算剩余时间
            p_tcb->TickRemain         =   p_tcb->TickCtrMatch - OSTickCtr;
            //计算的时间到就就绪
            if(OSTickCtr == p_tcb->TickCtrMatch){
                //让任务就绪
                 p_tcb->TaskState = OS_TASK_STATE_RDY;
                 //从时基表中删除
                 OS_TickListRemove(p_tcb);
                 OS_RdyListInsert(p_tcb);
            }else{
                flag = 0xff;
            }
            //指向下一个任务控制块
            p_tcb = p_tcb_next;
        }else{
            flag = 0xff;
        }
    }
    OS_CRITICAL_EXIT();
}

//延时函数
void OSTimeDly(CPU_UINT32 times)
{
  OS_ERR err;
  CPU_SR_ALLOC();
  OS_CRITICAL_ENTER(); 
  //从就绪表删除
  OS_TickListInset(OSTCBCurPtr,times,&err);
  OS_RdyListRemove(OSTCBCurPtr);
  OS_CRITICAL_EXIT();
  //进行一次任务调度
  OSSched();
}


